module StoreBuffer(

	input			i_SB_clk,
	input			i_SB_enable,
	input			i_SB_reset,
	//Stall
	output			o_SB_stall,
	//EnQueue
	input			i_SB_valid1,
	input	[2:0]	i_SB_StoreSize1,
	input	[31:0]	i_SB_StorePAddr1,
	input	[31:0]	i_SB_StoreData1,
	input			i_SB_valid2,
	input	[2:0]	i_SB_StoreSize2,
	input	[31:0]	i_SB_StorePAddr2,
	input	[31:0]	i_SB_StoreData2,
	//DeQueue
	output			o_SB_valid,
	output	[2:0]	o_SB_StoreSize,
	output	[31:0]	o_SB_StorePAddr,
	output	[31:0]	o_SB_StoreData,
	input			i_SB_DataOK

);
	
	reg			valid[63:0];
	reg	[2:0]	StoreSize[63:0];
	reg	[31:0]	StorePAddr[63:0];
	reg	[31:0]	StoreData[63:0];

	reg		[5:0]	EnQueuePointer;
	reg		[5:0]	DeQueuePointer;
	
	//EnQueue
	wire	[15:0]	EmptyList;
	begin:	emptylist
		reg	[7:0]	tempI;
		for(tempI=8'd0; tempI<=8'd15; tempI=tempI+8'd1)
			assign	EmptyList[tempI[3:0]] = ~valid[tempI[3:0]];
	end
	wire	Empty = (EmptyList==16'hffff);
	
	assign	o_SB_stall = ~Empty &&
						 (((DeQueuePointer==EnQueuePointer) && (i_SB_valid1 || i_SB_valid2) ||
						  ((DeQueuePointer==EnQueuePointer+4'd1) && i_SB_valid1 && i_SB_valid2));
	
	assign	o_SB_valid		= valid[DeQueuePointer];
	assign	o_SB_StoreSize	= StoreSize[DeQueuePointer];
	assign	o_SB_StorePAddr	= StorePAddr[DeQueuePointer];
	assign	o_SB_StoreData	= StoreData[DeQueuePointer];
	
always @(posedge i_SB_clk)
	begin
		if(i_SB_reset)
			begin:	reset
				reg	[7:0]	tempK;
				for(tempK=8'd0; tempK<=8'd63; tempK=tempK+8'd1)
					begin
						valid[tempK[5:0]]		<= 1'd0;
						StoreSize[tempK[5:0]]	<= 3'd0;
						StorePAddr[tempK[5:0]]	<= 32'd0;
						StoreData[tempK[5:0]]	<= 32'd0;
						//Pointers
						DeQueuePointer	<= 6'd0;
						EnQueuePointer  <= 6'd0;
					end
			end
		else if(i_SB_enable)
			begin
				//EnQueue
				if(~o_SB_stall && i_SB_valid1 && i_SB_valid2)
					begin
						valid[EnQueuePointer]		<= i_SB_valid1;
						StoreSize[EnQueuePointer]	<= i_SB_StoreSize1;
						StorePAddr[EnQueuePointer]	<= i_SB_StorePAddr1;
						StoreData[EnQueuePointer]	<= i_SB_StoreData1;
						
						valid[EnQueuePointer+6'd1]		<= i_SB_valid2;
						StoreSize[EnQueuePointer+6'd1]	<= i_SB_StoreSize2;
						StorePAddr[EnQueuePointer+6'd1]	<= i_SB_StorePAddr2;
						StoreData[EnQueuePointer+6'd1]	<= i_SB_StoreData2;
						//updata EnQueuePointer
						EnQueuePointer <= EnQueuePointer + 6'd2;
					end
				if(~o_SB_stall && i_SB_valid1 && ~i_SB_valid2)
					begin
						valid[EnQueuePointer]		<= i_SB_valid1;
						StoreSize[EnQueuePointer]	<= i_SB_StoreSize1;
						StorePAddr[EnQueuePointer]	<= i_SB_StorePAddr1;
						StoreData[EnQueuePointer]	<= i_SB_StoreData1;
						//updata EnQueuePointer
						EnQueuePointer <= EnQueuePointer + 6'd1;
					end
				if(~o_SB_stall && ~i_SB_valid1 && i_SB_valid2)
					begin
						valid[EnQueuePointer]		<= i_SB_valid2;
						StoreSize[EnQueuePointer]	<= i_SB_StoreSize2;
						StorePAddr[EnQueuePointer]	<= i_SB_StorePAddr2;
						StoreData[EnQueuePointer]	<= i_SB_StoreData2;
						//updata EnQueuePointer
						EnQueuePointer <= EnQueuePointer + 6'd1;
					end
				//DeQueue
				valid[DeQueuePointer]		<= 1'd0;
				StoreSize[DeQueuePointer]	<= 3'd0;
				StorePAddr[DeQueuePointer]	<= 32'd0;
				StoreData[DeQueuePointer]	<= 32'd0;
				
				if(i_SB_DataOK) DeQueuePointer <= DeQueuePointer + 6'd1;
			end
	end

endmodule